#ifndef __OBJECT_H__
#define __OBJECT_H__

#include "util/util_config.h"

NS_UTIL_BEGIN
class ObjectPtrBase;
class ObjectData;

class ObjectData
{
public:
	friend class ObjectPtrBase;
protected:
	int refCount;

public:
	ObjectData();
	virtual ~ObjectData();

public:
	virtual ObjectData* Clone()const;
};

class ObjectPtrBase
{
public:
	typedef ObjectPtrBase this_type;
protected:
	void incref();
	void decref();

protected:
	ObjectData* ptr;

public:
	ObjectData* get();				// Must return a base pointer!
	const ObjectData* get()const;	// Return a const pointer
	
	ObjectPtrBase();
	ObjectPtrBase(ObjectPtrBase& another_ptr);
	ObjectPtrBase(ObjectData* another_ptr);
	virtual ~ObjectPtrBase();
	
public:
	operator bool()const;

	this_type& operator= (this_type& data);
	this_type& operator= (ObjectData* data);

	ObjectData* operator->(){return ptr;}
	const ObjectData* operator->()const{return ptr;}

	operator ObjectData* ();		// This operator can be overrided.

public:
	virtual ObjectData* Clone()const=0;
};

// ObjectPtrT<T>
// T must be derived from ObjectData
template<typename T>
class ObjectPtrT : public ObjectPtrBase
{
public:
	typedef ObjectPtrBase base_type;
	typedef T data_type;
	typedef ObjectPtrT<T> this_type;
	typedef T* pointer_type;

public:
	ObjectPtrT():base_type(){}
	ObjectPtrT(this_type& another_ptr):base_type(another_ptr){}
	ObjectPtrT(data_type* another_ptr):base_type(dynamic_cast<ObjectData*>(another_ptr)){}

	operator data_type* (){return dynamic_cast<data_type*>(ptr);}
	operator bool()const
	{
		return ptr!=NULL;
	}
	this_type& operator= (this_type& data)
	{
		decref();
		ptr = dynamic_cast<data_type*>(data.get());
		incref();
		return *this;
	}
	this_type& operator= (data_type* data)
	{
		decref();
		ptr = dynamic_cast<ObjectData*>(data);
		incref();
		return *this;
	}
	data_type* operator->(){return (dynamic_cast<data_type*>(ptr));}
	const data_type* operator->()const{return (dynamic_cast<const data_type*>(ptr));}

	virtual ~ObjectPtrT(){}

public:
	virtual ObjectData* Clone()const
	{
		data_type* ret_ptr = new data_type(*(dynamic_cast<const data_type*>(ptr)));
		return dynamic_cast<ObjectData*>(ret_ptr);
	}
};

// 
class Object
{
public:
	virtual ~Object(){}
};

// ObjectT
// class O should derived from ObjectData
template<typename O>
class ObjectT : public Object
{
public:
	typedef ObjectT<O> this_type;
	typedef O data_type;
	typedef O* pointer_type;
public:
	ObjectT(){}
	virtual ~ObjectT()
	{}

	// default copy the reference(pointer) from obj
	ObjectT(this_type& obj)
	{
		ptr = obj.ptr;
	}

public:
	this_type __clone__() const
	{
		this_type ret;
		ret.ptr = dynamic_cast<data_type*>(ptr->Clone());
		return ret;
	}

public:
	data_type* get(){return ptr;}
	const data_type* get()const{return ptr;}

protected:
	ObjectPtrT<data_type> ptr;
};


NS_UTIL_END


#endif